#! /opt/local/bin/ruby
require 'rubygems'
require 'html5'
require 'html5/html5parser'
require 'html5/tokenizer'
require 'html5/treebuilders/rexml'
require 'html5/treewalkers/rexml'
require 'html5/treebuilders/simpletree'
require 'html5/treewalkers/simpletree'

class MyNode
  
  attr_accessor :tag, :data, :attributes, :next_sibling, :previous_sibling, 
                :parent, :has_children, :first_child, :children
  
  
  def initialize(tag)
    @tag = tag
    @data = ''
    @attributes = {}
    
    # siblings via a link list
    @next_sibling = nil
    @previous_sibling = nil

    # children 
    @has_children = false
    @parent = nil
    @first_child = nil
    @children = []
  end
  def to_s
      tag_attrs = ""
      if @attributes != nil
        @attributes.each {|k,v| tag_attrs << " "+k+'="'+v+'" '}
      end
  if @data != "" or self.has_children
      start_tag = "\n<#{@tag} #{tag_attrs}>\n"
      data = "#{@data}\n"
      #if self.has_children
      #  data += self.get_children_str
      #end
      end_tag = "</#{@tag}>\n"
      start_tag + data + end_tag
  else
    "<#{@tag} #{tag_attrs.strip}>"
  end
  end
  def print_all
    tag_attrs = ""
    if @attributes != nil
        @attributes.each {|k,v| tag_attrs << " "+k+'="'+v+'" '}
    end
  if @data != "" or self.has_children
      start_tag = "<#{@tag} #{tag_attrs}>\n"
      data = "#{@data}\n"
      if self.has_children
        data += self.get_children_str
      end
      end_tag = "</#{@tag}>\n"
      start_tag + data + end_tag
  else
    "<#{@tag} #{tag_attrs.strip}>"
  end
  
  
  end
  def get_children_str
     children_str = ""
     @children.each do |child|
    if child != nil
      children_str += "\n#{child.print_all}\n"
      end
    end
    children_str
  end
  
  def addParent(node)
    self.parent = node
  end
  
  def addData(data)
    @data += data
  end
  
  def addAttributes(attrs)
    attrs.each do |ary|
      #print "#{ary.class}\n"
      @attributes[ary[0]] = ary[1]
    end
  end
  def addChild(node)
  if self.first_child == nil
    self.first_child = node
  end
  self.children.push(node)
  self.has_children = true
  end
  
end


#TODO add open file or open URL for my tree processing
class MyTree
  attr_accessor :flattened_tree, :root
  def initialize()
    @root = nil
  @current_node = nil
    @tree = nil
    @node_queue = []
    @flattened_tree = []   
  end
  def parse_file(filename)
    data = File.new(filename).read()
  html_parser = HTML5::HTMLParser.new()
  html_parser.parse(data)
  self.parse(html_parser.tree)
  end
  
  def parse_url(url)
    #TODO implement this call
    raise "This call is not implemented yet!\n  Need to figure out how to parse the entire web page CSS and all!"
  end
  
  def parse(tree)
    walker = HTML5::TreeWalkers::REXML::TreeWalker.new(tree.get_document)
    walker.each do |node|
      if node[:type] == :StartTag
        #print "Adding a new node.\n"
          n = MyNode.new(node[:name])
          n.addAttributes(node[:data])
          if @current_node != nil
            @node_queue.push([@current_node.tag, @current_node])
            #print "Pushed #{node[:name]} #{n}\n"
              @current_node.addChild(n)
              n.parent = @current_node
          end         
      @flattened_tree.push(n)
          @current_node = n
          if @root == nil
            @root = @current_node
            #print "\nroot node set!\n"
          end
        elsif node[:type] == :EndTag
          tag,@current_node = @node_queue.pop()
          #print "Popped #{tag} \n"
        elsif node[:name] == nil and node[:type] != nil and node[:data] != nil
          @current_node.addData(node[:data])
        end
    end
    update_siblings(@root)
  
  end
  def print_page 
     @root.print_all
  end
  def update_siblings(parent)
  i = 0
  num_child = parent.children.length 
  if parent.has_children == false
    return
  end
  while i < num_child
        #print "#{parent.children[i]}\n"
    if parent.children[i].has_children
      update_siblings(parent.children[i])
    end
    parent.children[i].next_sibling = parent.children[(i+1+num_child)%num_child]
    parent.children[i].previous_sibling = parent.children[(i-1+num_child)%num_child]
    i+=1
  end
  end
  def find_node_tag(tag_name)
     flattened_tree.each do |node|
        if node.tag == tag_name
           return node
        end
     end
  end
  def find_all_node_tag(tag_name)
     nodes = []
     i = 0
     end_list = flattened_tree.length
     flattened_tree.each do |node|
        if node.tag == tag_name
           nodes.push( node)
        end
     end
     return nodes
  end

end
